package com.isky.visual.db.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.isky.visual.constant.CommonConstant;
import com.isky.visual.db.entity.DataStoreDimension;
import com.isky.visual.db.entity.Datastore;
import com.isky.visual.db.entity.Source;
import com.isky.visual.db.enums.DataStoreDimensionEnums;
import com.isky.visual.db.enums.DataStoreTypeEnum;
import com.isky.visual.db.factory.DbFactory;
import com.isky.visual.db.factory.IDbManager;
import com.isky.visual.db.mapper.DataStoreDimensionMapper;
import com.isky.visual.db.mapper.DatastoreMapper;
import com.isky.visual.db.mapper.SourceMapper;
import com.isky.visual.db.resolver.BaseDataSourceDimensionResolver;
import com.isky.visual.db.resolver.DefaultDataSourceDimensionResolver;
import com.isky.visual.db.resolver.ScatterDataSourceDimensionResolver;
import com.isky.visual.db.resolver.annotation.HandlerDataStoreResolver;
import com.isky.visual.db.service.IDatastoreService;
import com.isky.visual.db.vo.ReportModel;
import com.isky.visual.interceptor.PlatformUserManager;
import com.isky.visual.result.CodeMsg;
import com.isky.visual.result.ResultVo;
import com.isky.visual.user.entity.User;
import com.isky.visual.util.DBUtil;
import com.isky.visual.util.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.Connection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 结果集 服务实现类
 * </p>
 *
 * @author wudl
 * @since 2020-04-23
 */
@Service
public class DatastoreServiceImpl extends ServiceImpl<DatastoreMapper, Datastore> implements IDatastoreService {

    @Autowired
    SourceMapper sourceMapper;

    @Autowired
    DatastoreMapper datastoreMapper;

    @Autowired
    DataStoreDimensionMapper dataStoreDimensionMapper;

    private Map<Integer, BaseDataSourceDimensionResolver> dataStoreProcesser = null;

    @Autowired
    private void init(List<BaseDataSourceDimensionResolver> resolvers) {
        dataStoreProcesser = new HashMap<>();
        if (resolvers != null && !resolvers.isEmpty()) {
            for (BaseDataSourceDimensionResolver resolver : resolvers) {
                HandlerDataStoreResolver annotation = resolver.getClass().getAnnotation(HandlerDataStoreResolver.class);
                if (annotation != null) {
                    dataStoreProcesser.put(annotation.value(), resolver);
                }
            }
        }
    }

    private BaseDataSourceDimensionResolver getDataStoreDimensionResolver(Integer type) {
        Objects.requireNonNull(dataStoreProcesser, "数据集解析器未初始化");
        BaseDataSourceDimensionResolver baseDataSourceDimensionResolver = dataStoreProcesser.get(type);
        Objects.requireNonNull(baseDataSourceDimensionResolver, "没有编号为[" + type + "]的数据集解析器");
        return baseDataSourceDimensionResolver;
    }

    @Override
    public ResultVo<List<Datastore>> getAllDataStore() {
        User user = PlatformUserManager.getUser();
        QueryWrapper<Datastore> queryWrapper = new QueryWrapper<>();
        Datastore queryObject = new Datastore();
        queryObject.setValid(true);
        queryObject.setUserId(user.getId());
        queryWrapper.setEntity(queryObject);

        List<Datastore> datastores = datastoreMapper.selectList(queryWrapper);
        return ResultVo.success(datastores);
    }

    @Override
    public ResultVo<ReportModel> showDataStore(Long dataStoreId, Integer type) {
        if (dataStoreId == null) {
            return ResultVo.error(CodeMsg.QUERY_PARAMETER);
        }

        Datastore datastore = datastoreMapper.selectById(dataStoreId);
        if (datastore == null && !datastore.getValid()) {
            return ResultVo.error(CodeMsg.DATA_STORE_NULL);
        }

        Long dbId = datastore.getDbid();
        String sql = datastore.getSqls();

        QueryWrapper<DataStoreDimension> dataStoreDimensionWrappe = new QueryWrapper<>();
        DataStoreDimension dataStoreDimension = new DataStoreDimension();
        dataStoreDimension.setDataStoreId(datastore.getId());
        dataStoreDimensionWrappe.setEntity(dataStoreDimension);
        List<DataStoreDimension> dataStoreDimensions = dataStoreDimensionMapper.selectList(dataStoreDimensionWrappe);

        Map<String, String> dimensions = new HashMap<>();
        if (dataStoreDimensions != null && !dataStoreDimensions.isEmpty()) {
            Map<String, List<DataStoreDimension>> collect = dataStoreDimensions.stream()
                    .collect(Collectors.groupingBy(k -> k.getColumnType()));

            for (DataStoreDimensionEnums e : DataStoreDimensionEnums.values()) {
                String columnType = e.getColumnType();
                if (collect.containsKey(columnType)) {
                    dimensions.put(e.getColumnType(), collect.get(columnType).get(0).getColumnName());
                }
            }
        }
        Source source = sourceMapper.selectById(dbId);
        if (null == source) {
            return ResultVo.error(CodeMsg.DB_NOT_EXIST);
        }
        IDbManager dbManager = new DbFactory(source).getDbManager();
        Connection connection = dbManager.getConnection();
        ReportModel reportModel = getshowDataResult(connection, dimensions, sql, type);
        return ResultVo.success(reportModel);
    }

    @Override
    public ResultVo<Object> updateDataStore(Datastore datastore) {
        int updateById = datastoreMapper.updateById(datastore);
        if (updateById < 0) {
            return ResultVo.error(CodeMsg.DB_UPDATE_ERROR);
        } else {
            return ResultVo.success(CodeMsg.DB_UPDATE_SUCCESS);
        }
    }

    @Override
    public ResultVo<String> deleteDataStore(Long id) {
        int delete = datastoreMapper.logicDelete(id);
        if (delete < 0) {
            return ResultVo.error(CodeMsg.DB_DELETE_ERROR);
        }
        return ResultVo.success(CodeMsg.DB_DATA_SUCCESS.getMsg());
    }

    @Override
    public ResultVo<List<Datastore>> getUsedDataStore(Long userId) {
        QueryWrapper<Datastore> wrapper = new QueryWrapper<Datastore>();
        Datastore queryObject = new Datastore();
        queryObject.setUserId(userId);
        queryObject.setValid(true);
        wrapper.setEntity(queryObject);
        wrapper.orderByDesc("update_time");
        List<Datastore> datasource = datastoreMapper.selectList(wrapper);

        return ResultVo.success(datasource);
    }

    /**
     * @param connection
     * @param dimensionsMap
     * @param sql
     * @param type
     * @return
     */
    public ReportModel getshowDataResult(Connection connection, Map<String, String> dimensionsMap, String sql, Integer type) {
        ReportModel rm = null;
        try {
            if (type == null) {
                type = DataStoreTypeEnum.VIEW_TABLE_TYPE_DEFAULT.getType();
            }
            List<Map<String, Object>> selectMaps = DBUtil.query(connection, sql);
            rm = getDataStoreDimensionResolver(type).buildDataStoreDimension(selectMaps, dimensionsMap);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return rm;
    }
}
